#include "Data_Import.hpp"
#include "Genetic_Lib.hpp"

int main() {
// 0. 导入数据集、进行编码
// 首先得知有几个属性，每个属性有几个可能的取值
// 进行二进制编码
const string DATA_PATH = "tarin_data.txt";
importTrainData(DATA_PATH);

// 1. 已有的前提条件：
// 种群数量population、交叉比例cross_rate、变异比例mutation_rate
// 适合度函数Fitness()、适合度阈值Fitness_threshold
std::ifstream in("GA_set.ini", std::ios::in);
string line;
getline(in, line);
const int pop_num = stoi(line.substr(strlen("pop_num ")));
getline(in, line);
const double cross_rate = stod(line.substr(strlen("cross_rate ")));
getline(in, line);
const double mutation_rate = stod(line.substr(strlen("mutation_rate ")));
getline(in, line);
const double Fitness_threshold = stod(line.substr(strlen("Fitness_threshold ")));
in.close();
int count = 0;
cout << "------------------------------------------------------------------" << endl;
cout << "# Genetic_Algorithm test begins: " << endl;
cout << "------------------------------------------------------------------" << endl;
cout << "@ pop_num = " << pop_num << endl;
cout << "@ cross_rate = " << cross_rate << endl;
cout << "@ mutation_rate = " << cross_rate << endl;
cout << "@ Fitness_threshold = " << cross_rate << endl;
cout << "------------------------------------------------------------------" << endl;

// 2. 随机生成
// 种群P_set，用它的构造函数构造出population个假设
srand(time(NULL));  // 时间种子
Population P_set(pop_num);

// 3. 计算适合度
// P_set中每个假设计算适合度、和轮盘赌概率
P_set.Fitness();
P_set.Probabilities();

// 4. while循环
// 只要P_set中适合度最大的假设 < Fitness_threshold，就一直循环
while (P_set.get_maxFit().get_fitness() < Fitness_threshold) {
  // 4.1 构建新种群Pn_set，初始为空
  Population Pn_set;

  // 4.2 选择
  // 产生随机数
  // 依据轮盘赌概率，从P_set中选取（1-cross_rate）*
  // population个假设放入Pn_set中
  {
    vector<H_code> chooses = P_set.choose((1 - cross_rate) * pop_num);
    Pn_set.add(chooses);
  }

  // 4.3 交叉
  // 产生随机数
  // 依据轮盘赌概率，从P_set中选取 cross_rate * population/2
  // 对假设，放入临时容器中 每对使用交叉算子进行交叉，产生两个后代
  // 所有的后代都放到Pn_set中
  {
    vector<H_code> chooses = P_set.choose(cross_rate * pop_num);
    Cross(chooses);
    Pn_set.add(chooses);
  }

  // 4.4 变异
  // 在Pn_set中，用平均概率随机选择 mutation_rate * population 个假设
  // 每个假设都随机找一位进行反转
  Pn_set.mutate(mutation_rate * pop_num);

  // 4.5 更新
  // 将Pn_set赋给P_set，并销毁Pn_set
  P_set = Pn_set;

  // 4.6 计算适合度
  // P_set中每个假设计算适合度、和轮盘赌概率
  P_set.Fitness();
  P_set.Probabilities();
  ++count;
}
// 5. 退出循环后，返回适合度最大的假设
string res = P_set.get_maxFit().showCode();
cout << "# after " << count << " gennerations, here is the result: \n# ";
cout << decode(res) << "\n# Fitness = " << P_set.get_maxFit().get_fitness()
      << endl;
cout << "------------------------------------------------------------------" << endl;
return 0;
}